import './polyfill';

import { ConfigModule, ConfigService } from '@nestjs/config';
import { ConfigurationKeyPaths, getConfiguration } from './config/configuration';
import { LoggerModuleOptions, WinstonLogLevel } from './shared/logger/logger.interface';

import { AdminModule } from './modules/admin/admin.module';
import { BullModule } from '@nestjs/bull';
import { LOGGER_MODULE_OPTIONS } from './shared/logger/logger.constants';
// import { WSModule } from './modules/ws/ws.module';
import { LoggerModule } from './shared/logger/logger.module';
import { MissionModule } from './mission/mission.module';
import { Module } from '@nestjs/common';
import { SharedModule } from './shared/shared.module';
import { TypeORMLoggerService } from './shared/logger/typeorm-logger.service';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [getConfiguration],
      envFilePath: [`.env.${process.env.NODE_ENV}`, '.env'],
    }),
    // ! MongoDB 是无模式的，所以即使在配置参数开启了 synchronize，启动项目的时候也不会去数据库创建对应的表，所以不用奇怪，并没有出错，
    // ! 但 Mysql 在每次应用程序启动时自动同步表结构，容易造成数据丢失，生产环境记得关闭，以免造成无可预计的损失
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule, LoggerModule],
      useFactory: (
        configService: ConfigService<ConfigurationKeyPaths>,
        loggerOptions: LoggerModuleOptions,
      ) => ({
        autoLoadEntities: true,
        type: configService.get<any>('database.type'),
        host: configService.get<string>('database.host'),
        port: configService.get<number>('database.port'),
        username: configService.get<string>('database.username'),
        password: configService.get<string>('database.password'),
        database: configService.get<string>('database.database'),
        synchronize: configService.get<boolean>('database.synchronize'),
        logging: configService.get('database.logging'),
        timezone: configService.get('database.timezone'), // 时区
        // 自定义日志
        logger: new TypeORMLoggerService(configService.get('database.logging'), loggerOptions),
      }),
      inject: [ConfigService, LOGGER_MODULE_OPTIONS],
    }),
    BullModule.forRoot({}),
    // custom logger
    LoggerModule.forRootAsync(
      {
        imports: [ConfigModule],
        useFactory: (configService: ConfigService) => {
          return {
            level: configService.get<WinstonLogLevel>('logger.level'),
            consoleLevel: configService.get<WinstonLogLevel>('logger.consoleLevel'),
            timestamp: configService.get<boolean>('logger.timestamp'),
            maxFiles: configService.get<string>('logger.maxFiles'),
            maxFileSize: configService.get<string>('logger.maxFileSize'),
            disableConsoleAtProd: configService.get<boolean>('logger.disableConsoleAtProd'),
            dir: configService.get<string>('logger.dir'),
            errorLogName: configService.get<string>('logger.errorLogName'),
            appLogName: configService.get<string>('logger.appLogName'),
          };
        },
        inject: [ConfigService],
      },
      // global module
      true,
    ),
    // custom module
    SharedModule,
    // mission module
    MissionModule.forRoot(),
    // application modules import
    AdminModule,
    // websocket module
    // WSModule,
  ],
})
export class AppModule {}
